package org.dftproject.genesis.ui.pages.pedigree.zoom;

import java.util.List;

import org.eclipse.draw2d.AbstractLayout;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Cursors;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseListener;
import org.eclipse.draw2d.MouseMotionListener;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.graphics.Color;

public class ZoomBarFigure extends Figure {
	
	public static final Color backgroundColor = ColorConstants.listBackground;
	public static final Color lineColor = new Color(null, 192, 192, 192);
	
	private final int knobHeight = 11;
	
	private final ZoomManager zoomManager;
	private int position = 0;
	
	private final ZoomKnobFigure knob;
	
	public ZoomBarFigure(ZoomManager zoomManager) {
		this.zoomManager = zoomManager;
		this.setLayoutManager(new ZoomKnobLayout());
		
		knob = new ZoomKnobFigure();
		this.add(knob);
		
		zoomManager.addListener(new IZoomListener() {

			public void exponentChanged(ZoomManager zoomManager, float exponent) {
				position = 150 - (int) (150.0f * (exponent - zoomManager.getMinExponent()) / (zoomManager.getMaxExponent() - zoomManager.getMinExponent()));
				revalidate();
			}
			
		});
		
		setRequestFocusEnabled(true);
		addListeners();
	}

	protected void addListeners() {
		MouseTracker tracker = new MouseTracker();
		addMouseMotionListener(tracker);
		addMouseListener(tracker);
	}

	protected class MouseTracker extends MouseMotionListener.Stub implements MouseListener {

		private Point mouseLocation;
		private int knobPosition;

		public void mousePressed(MouseEvent me) {
			requestFocus();
			me.consume();

			mouseLocation = me.getLocation();
			if (!knob.getBounds().contains(mouseLocation)) {
				knobPosition = mouseLocation.y - getBounds().y - knobHeight / 2;
				setPosition(knobPosition);
			}
			
			knobPosition = getPosition();
		}

		public void mouseReleased(MouseEvent me) {
			revalidate();
		}

		public void mouseDoubleClicked(MouseEvent me) {
		}

		@Override
		public void mouseEntered(MouseEvent me) {
			setCursor(Cursors.HAND);
		}

		@Override
		public void mouseDragged(MouseEvent me) {
			Dimension delta = me.getLocation().getDifference(mouseLocation);
			setPosition(knobPosition + delta.height);
			revalidate();
		}

		@Override
		public void mouseExited(MouseEvent me) {
			setCursor(null);
		}

	}
	
	public int setPosition(int position) {
		this.position = position;
		if (this.position < 0)
			this.position = 0;
		else if (this.position > 150)
			this.position = 150;
		zoomManager.setExponent(zoomManager.getMinExponent() + (zoomManager.getMaxExponent() - zoomManager.getMinExponent()) * (150 - this.position) / 150.0f);
		return this.position;
	}
	
	public int getPosition() {
		return position;
	}
	
	@Override
	public void paint(Graphics graphics) {		
		Rectangle bounds = getBounds().getCopy().crop(new Insets(knobHeight / 2, 0, knobHeight / 2 + 1, 0));

		graphics.setForegroundColor(lineColor);
		graphics.drawLine(bounds.x + bounds.width / 2, bounds.y, bounds.x + bounds.width / 2, bounds.y + bounds.height - 1);
		
		for (int i = 0; i < 11; i++) {
			int indent = (int) Math.round(Math.pow(zoomManager.getScaleBase(), -i) * bounds.width / 2);
			graphics.drawLine(bounds.x + bounds.width / 2 - indent, bounds.y + i * 15, bounds.x + bounds.width / 2 + indent, bounds.y + i * 15);
		}

		super.paint(graphics);
	}
	
	protected class ZoomKnobLayout extends AbstractLayout {

		@Override
		protected Dimension calculatePreferredSize(IFigure container, int wHint, int hHint) {
			return new Dimension(wHint, 15 * 10 + 1 + knobHeight);
		}

		@SuppressWarnings("unchecked")
		public void layout(IFigure container) {
			List<IFigure> children = container.getChildren();
			if (children.size() != 1)
				return;
			
			Rectangle bounds = container.getBounds();
			
			IFigure child = children.get(0);
			child.setBounds(new Rectangle(bounds.x, bounds.y + position, bounds.width, knobHeight));
		}
		
	}

}
